/*
 * Zirco Browser for Android Copyright (C) 2010 - 2011 J. Devauchelle and contributors. This program is free software;
 * you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by
 * the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 */

package org.zirco.ui.activities;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.emergent.android.weave.client.WeaveAccountInfo;
import org.zirco.R;
import org.zirco.model.DbAdapter;
import org.zirco.model.adapters.WeaveBookmarksCursorAdapter;
import org.zirco.model.items.WeaveBookmarkItem;
import org.zirco.providers.BookmarksProviderWrapper;
import org.zirco.providers.WeaveColumns;
import org.zirco.sync.ISyncListener;
import org.zirco.sync.WeaveSyncTask;
import org.zirco.ui.activities.preferences.WeavePreferencesActivity;
import org.zirco.utils.ApplicationUtils;
import org.zirco.utils.Constants;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.LayoutAnimationController;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;

public class WeaveBookmarksListActivity extends Activity implements ISyncListener {

    private static final int                                                              MENU_SYNC        = Menu.FIRST;
    private static final int                                                              MENU_CLEAR       = Menu.FIRST + 1;

    private static final int                                                              MENU_OPEN_IN_TAB = Menu.FIRST + 10;
    private static final int                                                              MENU_COPY_URL    = Menu.FIRST + 11;
    private static final int                                                              MENU_SHARE       = Menu.FIRST + 12;

    private static final String                                                           ROOT_FOLDER      = "places";

    private LinearLayout                                                                  mNavigationView;
    private TextView                                                                      mNavigationText;
    private ImageButton                                                                   mNavigationBack;
    private ListView                                                                      mListView;

    private Button                                                                        mSetupButton;
    private Button                                                                        mSyncButton;

    private View                                                                          mEmptyView;
    private View                                                                          mEmptyFolderView;

    private List<WeaveBookmarkItem>                                                       mNavigationList;

    private ProgressDialog                                                                mProgressDialog;

    private DbAdapter                                                                     mDbAdapter;
    private Cursor                                                                        mCursor          = null;

    private WeaveSyncTask                                                                 mSyncTask;

    private static final AtomicReference<AsyncTask<WeaveAccountInfo, Integer, Throwable>> mSyncThread      = new AtomicReference<AsyncTask<WeaveAccountInfo, Integer, Throwable>>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.weave_bookmarks_list_activity);

        mNavigationView = (LinearLayout) findViewById(R.id.WeaveBookmarksNavigationView);
        mNavigationText = (TextView) findViewById(R.id.WeaveBookmarksNavigationText);
        mNavigationBack = (ImageButton) findViewById(R.id.WeaveBookmarksNavigationBack);
        mListView = (ListView) findViewById(R.id.WeaveBookmarksList);

        mNavigationBack.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                doNavigationBack();
            }
        });

        mListView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
                WeaveBookmarkItem selectedItem = BookmarksProviderWrapper.getWeaveBookmarkById(getContentResolver(), id);

                if (selectedItem != null) {
                    if (selectedItem.isFolder()) {
                        mNavigationList.add(selectedItem);
                        fillData();
                    } else {
                        String url = selectedItem.getUrl();

                        if (url != null) {
                            Intent result = new Intent();
                            result.putExtra(Constants.EXTRA_ID_NEW_TAB, false);
                            result.putExtra(Constants.EXTRA_ID_URL, url);

                            if (getParent() != null) {
                                getParent().setResult(RESULT_OK, result);
                            } else {
                                setResult(RESULT_OK, result);
                            }

                            finish();
                        }
                    }
                }
            }
        });

        mEmptyView = findViewById(R.id.WeaveBookmarksEmptyView);
        mEmptyFolderView = findViewById(R.id.WeaveBookmarksEmptyFolderView);

        // mListView.setEmptyView(mEmptyView);

        mSetupButton = (Button) findViewById(R.id.WeaveBookmarksEmptyViewSetupButton);
        mSetupButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                startActivity(new Intent(WeaveBookmarksListActivity.this, WeavePreferencesActivity.class));
            }
        });

        mSyncButton = (Button) findViewById(R.id.WeaveBookmarksEmptyViewSyncButton);
        mSyncButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                doSync();
            }
        });

        mNavigationList = new ArrayList<WeaveBookmarkItem>();
        mNavigationList.add(new WeaveBookmarkItem(
                                                  getResources().getString(R.string.WeaveBookmarksListActivity_WeaveRootFolder),
                                                  null, ROOT_FOLDER, true));

        mDbAdapter = new DbAdapter(this);
        mDbAdapter.open();

        registerForContextMenu(mListView);

        fillData();
    }

    @Override
    protected void onDestroy() {
        if (mCursor != null) {
            mCursor.close();
        }
        mDbAdapter.close();
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        MenuItem item = menu.add(0, MENU_SYNC, 0, R.string.WeaveBookmarksListActivity_MenuSync);
        item.setIcon(R.drawable.ic_menu_sync);

        item = menu.add(0, MENU_CLEAR, 0, R.string.WeaveBookmarksListActivity_MenuClear);
        item.setIcon(R.drawable.ic_menu_delete);

        return true;
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {

        switch (item.getItemId()) {
            case MENU_SYNC:
                doSync();
                return true;
            case MENU_CLEAR:
                doClear();
                return true;
            default:
                return super.onMenuItemSelected(featureId, item);
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        long id = ((AdapterContextMenuInfo) menuInfo).id;
        if (id != -1) {
            WeaveBookmarkItem item = BookmarksProviderWrapper.getWeaveBookmarkById(getContentResolver(), id);
            if (!item.isFolder()) {
                menu.setHeaderTitle(item.getTitle());

                menu.add(0, MENU_OPEN_IN_TAB, 0, R.string.BookmarksListActivity_MenuOpenInTab);
                menu.add(0, MENU_COPY_URL, 0, R.string.BookmarksHistoryActivity_MenuCopyLinkUrl);
                menu.add(0, MENU_SHARE, 0, R.string.Main_MenuShareLinkUrl);
            }
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

        WeaveBookmarkItem bookmarkItem = BookmarksProviderWrapper.getWeaveBookmarkById(getContentResolver(), info.id);

        switch (item.getItemId()) {
            case MENU_OPEN_IN_TAB:
                Intent i = new Intent();
                i.putExtra(Constants.EXTRA_ID_NEW_TAB, true);
                i.putExtra(Constants.EXTRA_ID_URL, bookmarkItem.getUrl());

                if (getParent() != null) {
                    getParent().setResult(RESULT_OK, i);
                } else {
                    setResult(RESULT_OK, i);
                }

                finish();
                return true;

            case MENU_COPY_URL:
                ApplicationUtils.copyTextToClipboard(this, bookmarkItem.getUrl(),
                                                     getString(R.string.Commons_UrlCopyToastMessage));
                return true;

            case MENU_SHARE:
                ApplicationUtils.sharePage(this, bookmarkItem.getTitle(), bookmarkItem.getUrl());
                return true;

            default:
                return super.onContextItemSelected(item);
        }
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                if (mNavigationList.size() > 1) {
                    doNavigationBack();
                    return true;
                } else {
                    return super.onKeyUp(keyCode, event);
                }
            default:
                return super.onKeyUp(keyCode, event);
        }
    }

    /**
     * Set the list loading animation.
     */
    private void setAnimation() {
        AnimationSet set = new AnimationSet(true);

        Animation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setDuration(75);
        set.addAnimation(animation);

        animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
                                           Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
        animation.setDuration(50);
        set.addAnimation(animation);

        LayoutAnimationController controller = new LayoutAnimationController(set, 0.5f);

        mListView.setLayoutAnimation(controller);
    }

    private void doSync() {
        String authToken = ApplicationUtils.getWeaveAuthToken(this);

        if (authToken != null) {
            WeaveAccountInfo info = WeaveAccountInfo.createWeaveAccountInfo(authToken);
            mSyncTask = new WeaveSyncTask(this, this);

            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.setTitle(R.string.WeaveSync_SyncTitle);
            mProgressDialog.setMessage(getString(R.string.WeaveSync_Connecting));
            mProgressDialog.setCancelable(true);
            mProgressDialog.setOnCancelListener(new OnCancelListener() {

                @Override
                public void onCancel(DialogInterface dialog) {
                    mSyncTask.cancel(true);
                }
            });

            mProgressDialog.show();

            boolean retVal = mSyncThread.compareAndSet(null, mSyncTask);
            if (retVal) {
                mSyncTask.execute(info);
            }

        } else {
            ApplicationUtils.showErrorDialog(this, R.string.Errors_WeaveSyncFailedTitle,
                                             R.string.Errors_WeaveAuthFailedMessage);
        }

    }

    private void doClear() {
        mProgressDialog = ProgressDialog.show(this, this.getResources().getString(R.string.Commons_PleaseWait),
                                              this.getResources().getString(R.string.Commons_ClearingBookmarks));

        new Clearer();

        // Reset last sync date.
        Editor lastSyncDateEditor = PreferenceManager.getDefaultSharedPreferences(this).edit();
        lastSyncDateEditor.putLong(Constants.PREFERENCE_WEAVE_LAST_SYNC_DATE, -1);
        lastSyncDateEditor.commit();
    }

    private void doNavigationBack() {
        mNavigationList.remove(mNavigationList.size() - 1);
        if (mNavigationList.size() == 0) {
            mNavigationList.add(new WeaveBookmarkItem(
                                                      getResources().getString(R.string.WeaveBookmarksListActivity_WeaveRootFolder),
                                                      null, ROOT_FOLDER, true));
        }

        fillData();
    }

    private void fillData() {

        String[] from = { WeaveColumns.WEAVE_BOOKMARKS_TITLE, WeaveColumns.WEAVE_BOOKMARKS_URL };
        int[] to = { R.id.BookmarkRow_Title, R.id.BookmarkRow_Url };

        mCursor = BookmarksProviderWrapper.getWeaveBookmarksByParentId(getContentResolver(),
                                                                       mNavigationList.get(mNavigationList.size() - 1).getWeaveId());

        ListAdapter adapter = new WeaveBookmarksCursorAdapter(this, R.layout.weave_bookmark_row, mCursor, from, to);

        if (adapter.isEmpty() && (mNavigationList.size() <= 1)) {
            mNavigationView.setVisibility(View.GONE);
        } else {
            mNavigationView.setVisibility(View.VISIBLE);
        }

        if (mNavigationList.size() > 1) {
            mNavigationBack.setEnabled(true);
            mListView.setEmptyView(mEmptyFolderView);
        } else {
            mNavigationBack.setEnabled(false);
            mListView.setEmptyView(mEmptyView);
        }

        mListView.setAdapter(adapter);

        setAnimation();

        mNavigationText.setText(getNavigationText());
    }

    private String getNavigationText() {
        StringBuilder sb = new StringBuilder();

        for (WeaveBookmarkItem navigationItem : mNavigationList) {
            if (sb.length() != 0) {
                sb.append(" > ");
            }

            sb.append(navigationItem.getTitle());
        }

        return sb.toString();
    }

    @Override
    public void onSyncCancelled() {
        mSyncThread.compareAndSet(mSyncTask, null);
        mProgressDialog.dismiss();
        fillData();

        if (mSyncTask.isFullSync()) {
            // Reset last sync date is this was a full sync.
            Editor lastSyncDateEditor = PreferenceManager.getDefaultSharedPreferences(this).edit();
            lastSyncDateEditor.putLong(Constants.PREFERENCE_WEAVE_LAST_SYNC_DATE, -1);
            lastSyncDateEditor.commit();
        }
    }

    @Override
    public void onSyncEnd(Throwable result) {
        mSyncThread.compareAndSet(mSyncTask, null);
        if (result != null) {
            String msg = String.format(getResources().getString(R.string.Errors_WeaveSyncFailedMessage),
                                       result.getMessage());
            Log.e("MainActivity: Sync failed.", msg);

            ApplicationUtils.showErrorDialog(this, R.string.Errors_WeaveSyncFailedTitle, msg);
        } else {
            Editor lastSyncDateEditor = PreferenceManager.getDefaultSharedPreferences(this).edit();
            lastSyncDateEditor.putLong(Constants.PREFERENCE_WEAVE_LAST_SYNC_DATE, new Date().getTime());
            lastSyncDateEditor.commit();
        }

        mProgressDialog.dismiss();
        fillData();
    }

    @Override
    public void onSyncProgress(int step, int done, int total) {
        switch (step) {
            case 0:
                mProgressDialog.setMessage(getString(R.string.WeaveSync_Connecting));
                break;
            case 1:
                mProgressDialog.setMessage(getString(R.string.WeaveSync_GettingData));
                break;
            case 2:
                mProgressDialog.setMessage(String.format(getString(R.string.WeaveSync_ReadingData), done, total));
                break;
            case 3:
                mProgressDialog.setMessage(getString(R.string.WeaveSync_WrittingData));
                break;
        }
    }

    private class Clearer implements Runnable {

        public Clearer(){
            new Thread(this).start();
        }

        @Override
        public void run() {
            BookmarksProviderWrapper.clearWeaveBookmarks(getContentResolver());

            mHandler.sendEmptyMessage(0);
        }

        private Handler mHandler = new Handler() {

                                     public void handleMessage(Message msg) {
                                         mProgressDialog.dismiss();
                                         fillData();
                                     }
                                 };

    }

}
